package cn.ljy.authority.service.impl;

import cn.ljy.authority.config.upload.FileUploadConfig;
import cn.ljy.authority.dao.BaseMapper;
import cn.ljy.authority.service.BaseService;
import cn.ljy.common.exception.model.MyWebException;
import cn.ljy.common.exception.model.base.MyRollBackException;
import cn.ljy.common.utils.page.Pagination;
import cn.ljy.common.utils.requests.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 公共业务的实现类
 * @param <T> 模块的实体类
 * @param <Q> 模块的实体查询类
 */
@Service
@Validated
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor= MyRollBackException.class)
@Slf4j
public abstract class IBaseService<T,Q> extends IBaseAuthService implements BaseService<T,Q> {
    @Autowired
    protected BaseMapper<T> mapper;
    @Autowired
    protected FileUploadConfig fileUploadConfig;
//    private IBaseService iBaseService = MySpringBeanUtil.getBean(IBaseService.class);

    /**
     * 获取资源的网址
     * @param filePath 文件存储在数据库的相对路径。例如：image/2024/09/66dd9dca9ad54776a256c068.png
     * @return 如果文件名为空，则返回文件名本身（也为空）
     */
    protected String getFileResourceWebUrl(String filePath){
        String imgWebUrl=null;
        if(StringUtils.hasLength(filePath)){
            imgWebUrl= RequestUtil.getBasePath() +fileUploadConfig.getResourceUploadUrl()+filePath;
        }
        return imgWebUrl;
    }

    @Override
    public Integer getTeacherRoleId(){
        return -11;
    }

    @Override
    public Integer getStudentRoleId(){
        return -12;
    }

    @Override
    public T get(@NotNull(message="传递参数不能为空") Serializable id) throws MyWebException {
        T result=null;
        //适合读取数据前的验证
        beforeGet(id);
        //从数据库读取记录
        result=mapper.findById(id);
        //读取后的数据处理，例如字段修改，添加关联属性
        if(result!=null){
            afterGet(result);
        }
        return result;
    }

    @Override
    public void save(@NotNull(message="传递参数不能为null") @Valid  T t) {
        //适合添加或更新数据前的验证，统一验证规则的可以放在这里
        beforeSaveOrUpdate(t);
        //适合保存数据前的验证
        beforeSave(t);
        //保存到数据库。执行后，添加后的主键会赋值在t上。如果不是自动递增的ID则不会，需要另行处理
        mapper.save(t);
        //保存数据后的处理
        afterSave(t);
        afterChange();
    }

    @Override
    public void update(@NotNull(message="传递参数不能为null") @Valid T t) {
        //适合添加或更新数据前的验证，统一验证规则的可以放在这里
        beforeSaveOrUpdate(t);
        //适合更新数据前的验证
        beforeUpdate(t);
        mapper.update(t);
        //更新数据后的处理
        afterUpdate(t);
        afterChange();
    }


    @Override
    public void delete(@NotEmpty(message = "操作失败：请选择要移除的记录") Serializable[] ids) {
        beforeDelete(ids);
        mapper.deleteByIdIn(ids);
        afterDelete(ids);
        afterChange();
    }

    @Override
    public void forceDelete(@NotEmpty(message = "操作失败：请选择要移除的记录") Serializable[] ids) {
        //在移除前删除所有关联记录，可以在这个before函数中执行
        beforeForceDelete(ids);
        mapper.deleteByIdIn(ids);
        afterChange();
    }

    @Override
    public List<T> findAll(Q query) {
        List<T> list=new ArrayList<>();
        beforeFindAll(query);
        list.addAll(mapper.findAll(query));
        afterFindAll(list);
        return list;
    }

    @Override
    public int count(Q query) {
        beforeFindAll(query);
        return mapper.count(query);
    }

    @Override
    public Pagination findAll(Integer page, Integer pageSize, Q query) {
        beforeFindAll(query);
        //验证并计算相关分页数据
        Pagination pagination = new Pagination(page, pageSize,mapper.count(query));
        //为当前页的数据集赋值
        pagination.setData(mapper.find(pagination.getOffset(),pagination.getPageSize(),query));
        //对账户信息进行相应处理
/*        pagination.getData().stream().forEach(user->{

        });*/
        afterFindAll(pagination.getData());
        return pagination;
    }

    //设置关联属性和计算属性，默认在afterfindall和get属性中
    protected void enrichEntityFields(T t){

    }

    //在get函数之前执行
    protected void beforeGet(Serializable id){

    }

    //在get函数之后执行
    protected void afterGet(T t){
        if(t!=null){
            this.enrichEntityFields(t);
        }
    }

    //在update函数之前执行
    protected void beforeUpdate(T t){

    }

    protected void afterUpdate(T t){}

    //在添加函数之前执行
    protected void beforeSave(T t){

    }

    //在添加函数之后执行
    protected void afterSave(T t){}


    protected void beforeDelete(Serializable[] ids){}

    protected void afterDelete(Serializable[] ids){}

    protected void beforeForceDelete(Serializable[] ids){}

    //在save或者update函数之前执行
    protected void beforeSaveOrUpdate(T t){

    }

    //20240728增加。在添加、编辑、删除后执行，设计意图是如果数据库中相应记录修改之后需要统一进行相关业务，则可采用此方法
    //设计本方法最开始目标是用于在权限进行改变后，能够自动刷新redis中的树形权限记录
    protected void afterChange(){}

    /*在findall函数之前执行*/
    protected void beforeFindAll(Q query){
    }

    /*在findall函数之后执行*/
    protected void afterFindAll(List<T> list){
        //补充属性
        list.stream().forEach(item->this.enrichEntityFields(item));
    }

}
